跳到主要内容

C# 扩展方法

扩展方法是什么?

扩展方法使你能够向现有类型 “添加” 方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。

扩展方法是一种静态方法,但可以像扩展类型上的实例方法一样进行调用。 对于用 C#、F# 和 Visual Basic 编写的客户端代码,调用扩展方法与调用在类型中定义的方法没有明显区别。

扩展方法的目的就是为一个现有类型添加一个方法,现有类型既可以是 int,string 等数据类型,也可以是自定义的数据类型。

添加一个方法的例子:一般来说,int 数据类型有个 Tostring 的方法,就是把 int 数据转换为字符串的类型,比如现在我们想在转换成字符串的时候还添加一点东西,比如增加一个字符 a 那么之前的 Tostring 就不好使了,因为它只是它我们的 int 数据转换为 string 类型的,却并不能添加一个字母 a 所以这就要用到所谓的扩展方法了。

定义和调用扩展方法

  1. 定义包含扩展方法的静态类。注意此类必须对客户端代码可见。
  2. 将扩展方法实现为静态方法,并且使其可见性至少与所在类的可见性相同。
  3. 此方法的第一个参数指定方法所操作的类型;此参数前面必须加上 this 修饰符。
  4. 在调用代码中,添加 using 指令,用于指定包含扩展方法类的命名空间。
  5. 和调用类型的实例方法那样调用这些方法。

请注意,第一个参数并不是由调用代码指定,因为它表示要在其上应用运算符的类型,并且编译器已经知道对象的类型。所以只需通过 n 提供形参 2 的实参。

使用示例

以下示例实现 CustomExtensions.StringExtension 类中名为 WordCount 的扩展方法。 此方法对 String 类进行操作,该类指定为第一个方法参数。

CustomExtensions 命名空间导入应用程序命名空间,并在 Main 方法内部调用此方法。

using System.Linq;
using System.Text;
using System;

namespace CustomExtensions
{
// Extension methods must be defined in a static class.
public static class StringExtension
{
// 这个就是拓展方法
// 第一个参数接受 “this” 修饰符并指定定义该方法的类型。
public static int WordCount(this String str)
{
return str.Split(new char[] {' ', '.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}

namespace Extension_Methods_Simple
{
// Import the extension method namespace.
using CustomExtensions;

class Program
{
static void Main(string[] args)
{
string s = "The quick brown fox jumped over the lazy dog.";
// Call the method as if it were an
// instance method on the type. Note that the first
// parameter is not specified by the calling code.
int i = s.WordCount();
System.Console.WriteLine("Word count of s is {0}", i);
}
}
}

示例:给 String 类型添加一个方法

//必须是静态类才可以添加扩展方法  
static class Program
{
// 声明扩展方法
// 扩展方法必须是静态的,Add 有三个参数
// this 必须有,string 表示我要扩展的类型,stringName 表示对象名
// 三个参数this和扩展的类型必不可少,对象名可以自己随意取如果需要传递参数,//再增加一个变量即可
public static string Add(this string stringName)
{
return stringName + "a";
}


static void Main(string[] args)
{
string str = "example";
// 注意调用扩展方法,必须用对象来调用
string Newstr = str.Add();
Console.WriteLine(Newstr);
Console.ReadKey();
}
}

示例:给自定义类型添加一个方法

首先声明一个 Student 类,它包含了两个方法 StuInfo、getStuInfo 实例代码如下:

public class Student
{
public string StuInfo()
{
return "学生基本信息";
}

public string getStuInfo(string stuName, string stuNum)
{
return string.Format("学生信息:\n" + "姓名:{0} \n" + "学号:{1}", stuName, stuNum);
}
}

之后我们再声明一个名为 ExtensionStudentInfo 的静态类,注意必须为静态 这个类的作用就是包含一些我们想要扩展的方法,在此我们声明两个 Student 类型的扩展方法,Student 类型为我们自定义的类型。

示例代码如下:

public static class ExtensionStudentInfo  
{
//声明扩展方法
//要扩展的方法必须是静态的方法,Add有三个参数
//this 必须有,string表示我要扩展的类型,stringName表示对象名
//三个参数this和扩展的类型必不可少,对象名可以自己随意取如果需要传递参数,再增加一个变量即可
public static string ExtensionStuInfo(this Student stuName)
{
return stuName.StuInfo();
}
//声明扩展方法
//要扩展的方法必须是静态的方法,Add有三个参数
//this 必须有,string表示我要扩展的类型,stringName表示对象名
//三个参数this和扩展的类型必不可少,对象名可以自己随意取如果需要传递参数,在此我们增加了两个string类型的参数
public static string ExtensionGetStuInfo(this Student student, string stuname, string stunum)
{
return student.getStuInfo(stuname, stunum)+"\n读取完毕";
}
}

以上的工作做完之后便可以使用我们的扩展方法了,注意必须要用对象来调用扩展方法。

static void Main(string[] args)
{
Student newstudent = new Student();
//要使用对象调用我们的扩展方法

string stuinfo = newstudent.ExtensionStuInfo();
Console.WriteLine(stuinfo);
//要使用对象调用我们的扩展方法

string stuinformation = newstudent.ExtensionGetStuInfo("example", "20081766");
Console.WriteLine(stuinformation);
Console.ReadKey();
}

使用注意点

扩展方法有就近原则,也就是如果在你的程序里有两个一模一样的扩展方法,一个和你的使用类是处于同一命名空间里,另外一个处于别的命名空间里,这个时候会优先使用同一命名空间里的扩展方法,也就是说 “血缘关系” 越近,越被青睐。

很多人看到扩展方法也许眼里冒出金光,以后在设计的时候不管三七二十一,反正可以扩展。还有一些人会对类任意扩展,将以前一些作为 ”Helper” 的方法统统使用扩展方法代替,注意的是扩展方法有 “污染性”,所以得在扩展的时候还是想想,是不是值得这样扩展。

在扩展的时候也不要对比较高层的类进行扩展,像上面对 object 的扩展就是不可取的,object 是所有类的基类,一经扩展,所有的类都被“污染”了。

Reference

参考资料 C# 扩展方法 参考资料 如何实现和调用自定义扩展方法(C# 编程指南)